/** @file    FormObjectFactory.cpp
 *  @author  Alessandro Polo
 *  @version $Id: FormObjectFactory.cpp 2867 2010-08-07 20:44:51Z alex $
 *  @brief
 * File containing methods for the wosh::gui::FormObjectFactory class.
 * The header for this class can be found in FormObjectFactory.h, check that file
 * for class description.
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/

 #include "FormObjectFactory.h"
 #include "ui_FormObjectFactory.h"
 #include <core/ObjectFactory.h>
 #include <core/List.h>

 #include <QtGui/QInputDialog>
 #include <QtGui/QMessageBox>


using namespace std;
namespace wosh {
 namespace gui {

 WOSH_REGISTER(wosh::gui::FormObjectFactory, "wosh::gui::IWidgetGeneric", 2.01, _static_FormObjectFactory )
 WOSH_GUI_MAP(wosh::gui::FormObjectFactory, "wosh::ObjectFactory", 2.00, _static_Map_FormObjectFactory )

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

FormObjectFactory::FormObjectFactory(QWidget *parent)
	: IWidgetGeneric(parent) {
	this->m_ui = new Ui::FormObjectFactory();
	this->m_ui->setupUi(this);

	IWidgetGeneric::setTargetURI(_ObjectFactory_URI);
	buildMenus();

	// tab ObjectAllocators [0]
	connect(this->m_ui->tableViewObjectAllocators, SIGNAL(postMessage(Message*)),this, SLOT(postMessage(Message*)) );
	connect(this->m_ui->btnAddAllocator, SIGNAL(clicked()), this, SLOT(btnAddAllocator_clicked()));
	connect(this->m_ui->btnRemoveAllocator, SIGNAL(clicked()), this, SLOT(btnRemoveAllocator_clicked()));
	connect(this->m_ui->btnAllocationQuery, SIGNAL(clicked()), this, SLOT(btnAllocationQuery_clicked()));
	connect(this->m_ui->btnAllocatorFind, SIGNAL(clicked()), this, SLOT(btnAllocatorFind_clicked()));

	// tab RTTI Tree [1]
	this->treeModel = new WoshObjectInfoTreeModel( NULL, this);
	this->m_ui->treeViewObjectTypes->setContextMenuPolicy(Qt::CustomContextMenu);
	connect(this->m_ui->treeViewObjectTypes, SIGNAL(customContextMenuRequested(const QPoint&)),this, SLOT(treeViewObjectTypes_ContextMenu(const QPoint&)) );
	this->m_ui->treeViewObjectTypes->setModel(this->treeModel);
	connect(this->m_ui->wUpBarObjectTypes, SIGNAL(updateClicked()), this, SLOT(refreshRTTI()));
	this->m_ui->cmbObjectAllocators->setModel(this->m_ui->tableViewObjectAllocators->getTableModel());
	this->m_ui->cmbObjectAllocators->setModelColumn(0);
	connect(this->m_ui->chkObjectTypesShowChildren, SIGNAL(clicked()), this, SLOT(refreshRTTI()));
 }

FormObjectFactory::~FormObjectFactory() {
	delete this->m_ui;
 }

void FormObjectFactory::changeEvent(QEvent *e) {
	QWidget::changeEvent(e);
	if ( e->type() == QEvent::LanguageChange )
		this->m_ui->retranslateUi(this);
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void FormObjectFactory::refreshAll() {
	this->setWindowTitle( QString("Object Factory [%1]").arg(this->getTargetURI().getKernelName().c_str()) );
	this->m_ui->tableViewObjectAllocators->refreshData();
	refreshRTTI();
 }

void FormObjectFactory::refreshRTTI() {
	QString context = this->m_ui->cmbObjectAllocators->currentText();
	bool show_childtree = this->m_ui->chkObjectTypesShowChildren->isChecked();
	List* args = List::createFrom<Variant>( context.toLatin1().data(), show_childtree );
	executeRemoteMethod( _SystemMonitor_METHOD_types_tree, args );
	this->m_ui->wUpBarObjectTypes->sayRetrieving();
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void FormObjectFactory::btnAddAllocator_clicked() {

 }

void FormObjectFactory::btnRemoveAllocator_clicked() {
	if ( !GuiUtilities::warning(tr("Remove Allocator.."), tr("This operation is still experimental. Continue?") ) )
		return;
	Variant allocatorID = this->m_ui->tableViewObjectAllocators->getCurrentItemAsVariantAtCol(0);
	executeRemoteMethod( _ObjectFactory_METHOD_remove_allocator, allocatorID.clone() );
 }

void FormObjectFactory::btnAllocationQuery_clicked() {
	bool ok;
	QString classname = QInputDialog::getText(this, tr("Query Allocation of.."), tr("ClassName (including namespace, case sensitive):"), QLineEdit::Normal, "wosh::", &ok);
	if ( !ok || classname.isEmpty() )
		return;
	doCheckAllocable(classname.toStdString());
 }

void FormObjectFactory::btnAllocatorFind_clicked() {
	bool ok;
	QString classname = QInputDialog::getText(this, tr("Find Allocator of.."), tr("ClassName (including namespace, case sensitive):"), QLineEdit::Normal, "wosh::", &ok);
	if ( !ok || classname.isEmpty() )
		return;
	doAllocatorFind(classname.toStdString());
 }

void FormObjectFactory::doCheckAllocable( const std::string& classname ) {
	Variant vClassname(classname);
	executeRemoteMethod( _SystemMonitor_METHOD_supports_type, vClassname );
 }

void FormObjectFactory::doAllocatorFind( const std::string& classname ) {
	Variant vClassname(classname);
	executeRemoteMethod( _SystemMonitor_METHOD_find_allocator, vClassname );
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void FormObjectFactory::buildMenus() {
	this->menuTitle = new QAction(this);
	this->menuTitle->setEnabled(false);

	this->menuCheckAllocable = new QAction(this);
	this->menuCheckAllocable->setText(tr("&Check Allocable"));
	this->menuFindAllocator = new QAction(this);
	this->menuFindAllocator->setText(tr("&Find Allocator"));
	this->menuGotoRootNode = new QAction(this);
	this->menuGotoRootNode->setText(tr("&Goto Root-Node"));
	this->menuGotoParent = new QAction(this);
	this->menuGotoParent->setText(tr("&Goto Parent-Node"));

	this->menuObjectType = new QMenu(this);
	this->menuObjectType->addAction(this->menuTitle);
	this->menuObjectType->addSeparator();
	this->menuObjectType->addAction(this->menuCheckAllocable);
	this->menuObjectType->addAction(this->menuFindAllocator);
	this->menuObjectType->addSeparator();
	this->menuObjectType->addAction(this->menuGotoRootNode);
	this->menuObjectType->addAction(this->menuGotoParent);
 }

void FormObjectFactory::treeViewObjectTypes_ContextMenu( const QPoint& pos )
 {
	QPoint globalPos = this->mapToGlobal(pos);
	QModelIndex index = this->m_ui->treeViewObjectTypes->indexAt(pos);
	if ( !index.isValid() || index.row() == 0 ) return;
	TreeNode* item = static_cast<TreeNode*>(index.internalPointer());
	if ( item == NULL || item->getContent() == NULL ) return;
	const ObjectTypeInfo* objinfo = item->getContent()->as<ObjectTypeInfo>();
	if ( objinfo == NULL ) return;
	this->menuTitle->setText( objinfo->name.c_str() );
	this->menuTitle->setIcon( GuiUtilities::createIconFor(objinfo->name) );
	this->menuGotoParent->setEnabled( !objinfo->parent.empty() );
	this->menuGotoRootNode->setEnabled( index.parent().isValid() );

	QAction* selected = this->menuObjectType->exec( globalPos );
	if ( selected == this->menuCheckAllocable )
		doCheckAllocable(objinfo->name);
	else if ( selected == this->menuFindAllocator )
		doAllocatorFind(objinfo->name);

	else if ( selected == this->menuGotoParent ) {
		QModelIndex inode = this->treeModel->indexOf(objinfo->parent, 0);
		this->m_ui->treeViewObjectTypes->setCurrentIndex(inode);
	 }
	else if ( selected == this->menuGotoRootNode ) {
		QModelIndex inode = this->treeModel->indexOf(objinfo->name, 0);
		this->m_ui->treeViewObjectTypes->setCurrentIndex(inode);
	 }
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void FormObjectFactory::busMessage( const Message& message, const Bus* ) {
	if ( message.isEmpty() || !message.getContent()->isResponse() ) return;
	if ( !isMessageForMeOrFromTarget(message) ) return;
	const wosh::Response* response = message.getContent()->asResponse();

	this->m_ui->tableViewObjectAllocators->evalResponse(response);

	if ( response->getMethod() == _SystemMonitor_METHOD_supports_type ) {
		if ( WSUCCEEDED(response->getReturnValue()) )
			QMessageBox::information(this, tr("Query Allocation of -.."), tr("The Class is allocable.") );
		else
			QMessageBox::warning(this, tr("Query Allocation of -.."), tr("FAILED. Class is defined abstract.") );
		return;
	 }
	else if ( response->getMethod() == _SystemMonitor_METHOD_find_allocator ) {
		if ( WSUCCEEDED(response->getReturnValue()) ) {
			QString allocator = "Unknown";
			if ( response->hasData() && response->getData()->as<Variant>() != NULL )
				allocator = response->getData()->as<Variant>()->toString().c_str();
			QMessageBox::information(this, tr("Find Allocator of -.."), tr("The Class is registered in allocator %1.").arg(allocator) );
		 }
		else
			QMessageBox::warning(this, tr("Find Allocator of -.."), tr("FAILED. Allocator can't be found (is type registered?)!") );
		return;
	 }
	else if ( response->getMethod() == _SystemMonitor_METHOD_types_tree ) {
		if ( !response->hasData() ) return;
		if ( !response->getData()->isKindOf<Tree>() ) return;
		this->treeModel->loadTree( response->getData()->as<Tree>() );
		this->m_ui->treeViewObjectTypes->header()->setResizeMode(0, QHeaderView::Stretch);
		this->m_ui->treeViewObjectTypes->resizeColumnToContents(0);
		this->m_ui->wUpBarObjectTypes->sayReady();
		return;
	 }
	promptMethodResponse(message);
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

 }; // namespace gui
}; // namespace wosh
